#include "hzpch.h"
#include "WindowsWindow.h"
#include "SourceCode/Events/KeyEvent.h"
#include "SourceCode/Events/MouseEvent.h"
#include "SourceCode/Events/ApplicationEvent.h"
#include "SourceCode/Platforms/OpenGL/OpenGLContext.h"

namespace Hazal
{
	static bool s_GLFWInitialized = false;

	static void GLFWErrorCallback(int error_code, const char* description)
	{
		LOG_CORE_ERROR("GLFW error ({0}) : {1}", error_code, description);
	}

	CWindow* CWindow::Create(const SWindowProps& props)
	{
		return new CWindowsWindow(props);
	}

	CWindowsWindow::CWindowsWindow(const SWindowProps& props) : m_fLastFrameTime(0.0f)
	{
		HZ_PROFILE_FUNCTION()

		Init(props);
	}

	CWindowsWindow::~CWindowsWindow()
	{
		if (nullptr != m_pContext)
		{
			delete m_pContext;
			m_pContext = nullptr;
		}

		Shutdown();
	}

	void CWindowsWindow::Init(const SWindowProps& props)
	{
		m_Data.m_strTitle = props.m_strTitle;
		m_Data.m_unWidth = props.m_unWidth;
		m_Data.m_unHeight = props.m_unHeight;

		LOG_CORE_TRACE("Create window {0}({1}, {2})",
			props.m_strTitle, props.m_unWidth, props.m_unHeight);

		if (!s_GLFWInitialized)
		{
			int nSuccess = glfwInit();
			HZ_CORE_ASSERT(nSuccess, "Could not initialize GLFW!");

			/// 设置GLFW错误回调
			glfwSetErrorCallback(GLFWErrorCallback);

			s_GLFWInitialized = true;

			/// 创建GLFW窗口
			m_Window = glfwCreateWindow((int)props.m_unWidth, (int)props.m_unHeight, props.m_strTitle.c_str(), nullptr, nullptr);

			/// 创建OpenGL上下文对象
			m_pContext = new COpenGLContext(m_Window);
			m_pContext->Init();
		
			glfwSetWindowUserPointer(m_Window, &m_Data);	/// 传递m_Data结构体到回调函数
			SetVSync(true);									/// 打开垂直同步

			/// 设置GLFW窗口大小变化的回调
			glfwSetWindowSizeCallback(m_Window, [](GLFWwindow* window, int nWidth, int nHeight)
			{
				SWindowData& wData = *(SWindowData*)glfwGetWindowUserPointer(window);
				wData.m_unWidth = nWidth;
				wData.m_unHeight = nHeight;

				CWindowResizeEvent event(nWidth, nHeight);
				wData.m_eventCallback(event);
			});

			/// 设置窗口关闭的回调
			glfwSetWindowCloseCallback(m_Window, [](GLFWwindow* window)
			{
				SWindowData& wData = *(SWindowData*)glfwGetWindowUserPointer(window);

				CWindowCloseEvent event;
				wData.m_eventCallback(event);
			});

			/// 设置键盘回调
			glfwSetKeyCallback(m_Window, [](GLFWwindow* window, int key, int scancode, int action, int mods)
			{
				SWindowData& wData = *(SWindowData*)glfwGetWindowUserPointer(window);

				switch (action)
				{
					case GLFW_PRESS:
					{
						CKeyPressedEvent event(key, 0);
						wData.m_eventCallback(event);
						break;
					}
					case GLFW_RELEASE:
					{
						CKeyReleasedEvent event(key);
						wData.m_eventCallback(event);
						break;
					}
					case GLFW_REPEAT:
					{
						CKeyPressedEvent event(key, 1);
						wData.m_eventCallback(event);
						break;
					}
					default:
						break;
				}

			});

			glfwSetCharCallback(m_Window, [](GLFWwindow* window, unsigned int codepoint)
			{
				SWindowData& wData = *(SWindowData*)glfwGetWindowUserPointer(window);

				CKeyTypedEvent event(codepoint);

				wData.m_eventCallback(event);
			});

			/// 设置鼠标按钮回调
			glfwSetMouseButtonCallback(m_Window, [](GLFWwindow* window, int button, int action, int mods)
			{
				SWindowData& wData = *(SWindowData*)glfwGetWindowUserPointer(window);

				switch (action)
				{
					case GLFW_PRESS:
					{
						CMouseButtonPressedEvent event(button);
						wData.m_eventCallback(event);
						break;
					}
					case GLFW_RELEASE:
					{
						CMouseButtonReleasedEvent event(button);
						wData.m_eventCallback(event);
						break;
					}
					default:
						break;
				}
			});


			/// 设置鼠标滚轮回调
			glfwSetScrollCallback(m_Window, [](GLFWwindow* window, double xoffset, double yoffset)
			{
				SWindowData& wData = *(SWindowData*)glfwGetWindowUserPointer(window);

				CMouseScrolledEvent event(static_cast<float>(xoffset), static_cast<float>(yoffset));
				wData.m_eventCallback(event);
			});

			/// 设置鼠标指针位置变化的回调
			glfwSetCursorPosCallback(m_Window, [](GLFWwindow* window, double xpos, double ypos)
			{
				SWindowData& wData = *(SWindowData*)glfwGetWindowUserPointer(window);

				CMouseMovedEvent event(static_cast<float>(xpos), static_cast<float>(ypos));
				wData.m_eventCallback(event);
			});

		}
	}

	void CWindowsWindow::Shutdown()
	{
		glfwTerminate();
	}

	void CWindowsWindow::OnUpdate()
	{
		glfwPollEvents();			/// 触发窗口事件的回调

		m_pContext->SwapBuffers();	/// 由上下文管理交换缓冲区
	}

	void CWindowsWindow::SetVSync(bool bEnable)
	{
		if (bEnable)
		{
			glfwSwapInterval(1);	/// 交换缓冲区之前等待的帧数(垂直同步)
		}
		else
		{
			glfwSwapInterval(0);
		}

		m_Data.m_bVsync = bEnable;
	}

	bool CWindowsWindow::IsVSync() const
	{
		return m_Data.m_bVsync;
	}
	void* CWindowsWindow::GetNativeWindow() const
	{
		return m_Window;
	}
}